// ============================================================================
//
// Copyright (C) 2006-2007 Dengues
//
// Google Group: http://groups.google.com/group/dengues
// QQ Group: 24885404
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// ============================================================================
package org.dengues.core.resource;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.dengues.core.ExceptionOperation;
import org.dengues.core.runprocess.JavaProcessorUtil;
import org.dengues.core.warehouse.ENodeCategoryName;
import org.dengues.core.warehouse.IWarehouseNode;
import org.dengues.model.project.ProjectType;
import org.dengues.model.warehouse.ScriptsStorage;
import org.dengues.model.warehouse.Storage;
import org.dengues.model.warehouse.WarehousePackage;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;

/**
 * Qiang.Zhang.Adolf@gmail.com class global comment. Detailled comment <br/>
 * 
 * $Id: Dengues.epf 2007-12-4 qiang.zhang $
 * 
 */
public final class DenguesResourceManager {

    private static ResourceSet resourceSet = new ResourceSetImpl();

    /** Java Classes Directory. */
    public static final String JAVA_CLASSES_DIRECTORY = "classes"; //$NON-NLS-1$

    /** Java Source Directory. */
    public static final String JAVA_SRC_DIRECTORY = "src"; //$NON-NLS-1$

    public static final String PROJECT_EXTENSION = "project"; //$NON-NLS-1$

    public static final String SQL_EXTENSION = "sql"; //$NON-NLS-1$

    public static final String SEPERATOR = "_"; //$NON-NLS-1$

    private static final String RESOURCE = "resource"; //$NON-NLS-1$

    private static final String PLATFORM = "platform"; //$NON-NLS-1$

    /**
     * Qiang.Zhang.Adolf@gmail.com DenguesResourceManager constructor comment.
     */
    public DenguesResourceManager() {
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "initDenguesProject".
     * 
     * @param prj
     * @param comment
     * @throws CoreException
     */
    public static void initDenguesProject(IProject prj, String comment) throws CoreException {
        if (!prj.exists()) {
            final IWorkspace workspace = ResourcesPlugin.getWorkspace();
            final IProjectDescription desc = workspace.newProjectDescription(prj.getName());
            desc.setNatureIds(new String[] { DenguesProjectNature.ID });
            desc.setComment(comment);
            prj.create(desc, null);
            prj.open(IResource.BACKGROUND_REFRESH, null);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "createTypeResource".
     * 
     * @param process
     * @param project
     * @param path
     * @param name
     * @return
     */
    public Resource createStorageResource(Storage storage, IProject project, IPath path, ENodeCategoryName name) {
        URI itemResourceURI = getStorageResourceURI(project, name, path, storage);
        return resourceSet.createResource(itemResourceURI);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getStorageResourceURI".
     * 
     * @param project
     * @param name
     * @param path
     * @param storage
     * @return
     */
    private URI getStorageResourceURI(IProject project, ENodeCategoryName name, IPath path, Storage storage) {
        IPath folderPath = getFolderPath(project, name, path);
        String label = storage.getUuid();
        StringBuffer stringBuffer = getFileName(name, label);
        IPath file = folderPath.append(stringBuffer.toString()).addFileExtension(name.getExtension());
        return URI.createPlatformResourceURI(file.toOSString());
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFolderPath".
     * 
     * @param project
     * @param name
     * @param path
     * @return
     */
    private IPath getFolderPath(IProject project, ENodeCategoryName name, IPath path) {
        IFolder folder2 = project.getFolder(name.getName());
        switch (name) {
        case DATABASE:
        case CSVFILE:
        case XMLFILE:
        case EXCELFILE:
            folder2 = project.getFolder(ENodeCategoryName.DATASOURCE.getName()).getFolder(name.getName());
        }
        IFolder folder = folder2.getFolder(path);
        return folder.getFullPath();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFolder".
     * 
     * @param project
     * @param name
     * @param force
     * @return
     */
    public IFolder getFolder(IProject project, ENodeCategoryName name, boolean force) {
        IFolder processFolder = project.getFolder(name.getName());
        switch (name) {
        case DATABASE:
        case CSVFILE:
        case XMLFILE:
        case EXCELFILE:
            processFolder = project.getFolder(ENodeCategoryName.DATASOURCE.getName()).getFolder(name.getName());
        }
        if (force && !processFolder.exists()) {
            throw new RuntimeException("this folder: " + processFolder.getFullPath().toOSString() + " is not exits."); //$NON-NLS-1$ //$NON-NLS-2$
        }
        return processFolder;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "saveResource".
     * 
     * @param itemResource
     */
    public void saveResource(Resource itemResource) {
        try {
            itemResource.save(Collections.EMPTY_MAP);
        } catch (Exception e) {
            ExceptionOperation.operate(e);
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getTypeResource".
     * 
     * @param type
     * @return
     */
    public Resource getStorageResource(Storage storage, ENodeCategoryName name) {
        URI itemResourceURI = getStorageResourceURI(storage.eResource().getURI(), name.getExtension());
        Resource itemResource = resourceSet.getResource(itemResourceURI, false);
        if (itemResource == null) {
            itemResource = resourceSet.getResource(itemResourceURI, true);
        }
        return itemResource;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getStorageResourceURI".
     * 
     * @param uri
     * @param extension
     * @return
     */
    private URI getStorageResourceURI(URI uri, String extension) {
        return uri.trimFileExtension().appendFileExtension(extension);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFileName".
     * 
     * @param name
     * @param label
     * @return
     */
    public StringBuffer getFileName(ENodeCategoryName name, String label) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(label);
        stringBuffer.append(SEPERATOR);
        stringBuffer.append(name.getVersion());
        return stringBuffer;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "deleteResource".
     * 
     * @param resource
     */
    public void deleteResource(Resource resource) {
        deleteFile(getFile(resource.getURI()));
        resourceSet.getResources().remove(resource);
    }

    public static void resetResourceSet() {
        resourceSet = new ResourceSetImpl();
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "deleteFile".
     * 
     * @param file
     */
    private static void deleteFile(IFile file) {
        try {
            file.delete(true, false, null);
        } catch (CoreException e) {
            e.printStackTrace();
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFile".
     * 
     * @param uri
     * @return
     */
    private static IFile getFile(URI uri) {
        IPath path = convert(uri);
        if (path != null) {
            return ResourcesPlugin.getWorkspace().getRoot().getFile(path);
        }
        return null;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "convert".
     * 
     * @param uri
     * @return
     */
    private static IPath convert(URI uri) {
        if (PLATFORM.equals(uri.scheme()) && uri.segmentCount() > 1 && RESOURCE.equals(uri.segment(0))) {
            StringBuffer platformResourcePath = new StringBuffer();
            for (int i = 1, size = uri.segmentCount(); i < size; ++i) {
                platformResourcePath.append('/');
                platformResourcePath.append(URI.decode(uri.segment(i)));
            }

            return new Path(platformResourcePath.toString());
        }

        return null;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getProject".
     * 
     * @param prjName
     * @return
     */
    private static IProject getProject(String prjName) {
        IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
        return root.getProject(prjName);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getSqlScriptFile".
     * 
     * @param name
     * @return
     */
    public static IFile getSqlScriptFile(String name) {
        IProject project = getProject(JavaProcessorUtil.JAVA_PROJ_NAME);
        IFolder scripFolder = getFolder(project, new Path(JavaProcessorUtil.SQL_SCRIPT_DIR));
        IFile file = scripFolder.getFile(DenguesProjectFactory.getDenguesProject().getName() + SEPERATOR + name
                + "." + SQL_EXTENSION); //$NON-NLS-1$
        return file;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getFolder".
     * 
     * @param folder
     * @param path
     * @return
     */
    private static IFolder getFolder(IContainer folder, IPath path) {
        if (path.segmentCount() == 1) {
            IFolder folder2 = folder.getFolder(path);
            if (!folder2.exists()) {
                try {
                    folder2.create(true, false, null);
                } catch (CoreException ex) {
                    ex.printStackTrace();
                }
            }
            return folder2;
        } else {
            IFolder folder2 = folder.getFolder(new Path(path.segment(0)));
            if (!folder2.exists()) {
                try {
                    folder2.create(true, false, null);
                } catch (CoreException ex) {
                    ExceptionOperation.operate(ex);
                }
            }
            return getFolder(folder2, path.removeFirstSegments(1));
        }
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getWarehouseFile".
     * 
     * @param node
     * @return
     */
    public IFile getWarehouseFile(IWarehouseNode node) {
        IFolder folder = getFolder(WarehouseResourceFactory.getProject(), node.getCategoryName(), false);
        IFolder folder2 = folder;
        if (node.getWarehousePath().segmentCount() > 0) {
            folder2 = getFolder(folder, node.getWarehousePath());
        }
        String fileName = getFileName(node.getCategoryName(), node.getLabel()).toString();
        switch (node.getCategoryName()) {
        case DATABASE:
        case PROCESS:
            fileName += "." + node.getCategoryName().getExtension(); //$NON-NLS-1$
            break;
        default:
            break;
        }
        try {
            IResource[] members = folder2.members();
            for (IResource resource : members) {
                if (resource instanceof IFile) {
                    IFile f = (IFile) resource;
                    if (f.getName().equals(node.getLabel())) {
                        return f;
                    }
                }
            }
        } catch (CoreException e) {
            ExceptionOperation.operate(e);
        }
        IFile file = folder2.getFile(fileName);
        return file;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getTypeResource".
     * 
     * @param type
     * @return
     */
    public Resource getTypeResource(ProjectType type) {
        URI itemResourceURI = getProjectResourceURI(type.eResource().getURI());
        Resource itemResource = resourceSet.getResource(itemResourceURI, false);
        if (itemResource == null) {
            itemResource = resourceSet.getResource(itemResourceURI, true);
        }
        return itemResource;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getProcessResourceURI".
     * 
     * @param propertyResourceURI
     * @return
     */
    private URI getProjectResourceURI(URI propertyResourceURI) {
        return propertyResourceURI.trimFileExtension().appendFileExtension(PROJECT_EXTENSION);
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "loadEmfFromFile".
     * 
     * @param file
     * @param string
     * @return
     */
    public Storage loadStorage(IFile file, ENodeCategoryName name) {
        if (file.getFileExtension().equals(name.getExtension())) {
            Resource resource = resourceSet.getResource(URI.createPlatformResourceURI(file.getFullPath().toString()), true);
            Storage objectByType = (Storage) EcoreUtil.getObjectByType(resource.getContents(), WarehousePackage.eINSTANCE
                    .getStorage());
            return objectByType;
        }
        return null;
    }

    /**
     * Qiang.Zhang.Adolf@gmail.com Comment method "getAffectedReports".
     * 
     * @param type
     * @return
     */
    public List<Resource> getAffectedStorages(Storage type) {
        EcoreUtil.resolveAll(type);
        List<Resource> resources = new ArrayList<Resource>();
        Resource propertyResource = type.eResource();
        ENodeCategoryName name = ENodeCategoryName.PROCESS;
        name = ENodeCategoryName.getENodeCategory(type.getCategoryName());
        if (type instanceof ScriptsStorage) {
            name = ENodeCategoryName.SCRIPTS;
        }
        URI itemResourceURI = getStorageResourceURI(propertyResource.getURI(), name.getExtension());
        Resource itemResource = resourceSet.getResource(itemResourceURI, true);
        resources.add(itemResource);
        resources.add(propertyResource);

        return resources;
    }

}
